# -*- coding: utf-8 -*-
import os, logging, re
from datetime import datetime
from django.db import transaction
from django.conf import settings
from docs.utils import open_cmd, split_rst_file, update_docs_in_db

logging.basicConfig(level=logging.DEBUG,
                    format='%(message)s',
                    )

class BaseHandler(object):
    def __init__(self, project):        
        self.project = project
#        self.want_from_v = want_from_v
#        self.want_to_v = want_to_v
#        self.want_step = want_step

#        else:
#            logging.basicConfig(level=logging.INFO,
#                                format='%(message)s',
#                                )
#        if not os.path.exists(os.path.join(logs_dir, project.slug)):
#            os.mkdir(os.path.join(logs_dir, project.slug))
#        log_file = "%s-%s-%s.txt" % (want_from_v, want_to_v, datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))
#        log_handler = logging.FileHandler(os.path.join(logs_dir, project.slug, log_file))
#        log_handler.setLevel(logging.INFO)
#        formatter = logging.Formatter('%(message)s')
#        log_handler.setFormatter(formatter)
#        logging.getLogger().addHandler(log_handler)
        
    def handle(self, *args, **options):
        """
        The actual logic of the handler. Subclasses must implement
        this method.
        """
        raise NotImplementedError()
    
class SubversionHandler(BaseHandler):
    original_docs_dir_name = settings.ORIGINAL_DOCS_DIR_NAME
    
    def __init__(self, project, want_to_version = 'HEAD'):
        self.project = project
        self.from_version = project.current_version
        self.want_to_version = want_to_version
        self.docs_dir = project.docs_dir
        self.svn_docs_dir = project.original_docs_dir
        
    def get_version_in_svn_docs_dir(self):
        os.chdir(self.svn_docs_dir)
        m = re.search(r'revision="(\d+)"', open_cmd("svn", "info", "--xml").read())
        return int(m.group(1))
    
    def update(self, version = 'HEAD'):
        os.chdir(self.svn_docs_dir)
        return open_cmd("svn", "update", "-r", str(version), "--ignore-externals")
    
    def checkout(self, version = 'HEAD'):
        os.chdir(self.docs_dir)
        return open_cmd("svn", "co", "-r", str(version), "--ignore-externals", self.project.repository_url, SubversionHandler.original_docs_dir_name)

    def sync_to_current_version_in_db(self):
        logging.debug("sync svn doc dir to current version in database.")
        logging.debug("current version in database is %s." % self.from_version)
        if self.from_version:
            if os.path.exists(self.svn_docs_dir):
                current_version_in_svn_docs_dir = self.get_version_in_svn_docs_dir()
                logging.debug("current version in docs dir is %s." % current_version_in_svn_docs_dir)
                if self.from_version != current_version_in_svn_docs_dir:
                    self.update(self.from_version)
            else:
                logging.debug("current no docs dir is %s.")
                self.checkout(self.from_version)
        else:
            if os.path.exists(self.svn_docs_dir):
                open_cmd("rm","-rf", self.svn_docs_dir)
    
    def handle_lines(self, lines):
        docs_files = []
        status_count = {"A":0, "U":0, "D":0}
        for line in lines:
            m = re.match(r"([a-zA-Z\s]{2})\s+(.+)", line)
            status, path = m.group(1)[0], m.group(2)
            path = path.strip()
            if not self.from_version: path = path.replace(SubversionHandler.original_docs_dir_name + os.sep, "")
            if self.project.is_doc_file(path) and status.upper() in status_count.keys():
                logging.info("%s       : %s" % (status, path))
                doc_file_path = os.path.join(self.svn_docs_dir, path)
                docs_files.append((path, status, split_rst_file(doc_file_path)))
                status_count[status.upper()] += 1
                
        return docs_files
    
    @transaction.commit_manually
    def handle(self, *args, **options):
        if self.want_to_version != 'HEAD' and self.from_version >= self.want_to_version:
            logging.debug("no need to update from version %s to version %s." , self.from_version, self.want_to_version)
            return
        self.sync_to_current_version_in_db()
        if self.from_version:
            f = self.update(self.want_to_version)
        else:
            f = self.checkout(self.want_to_version)
        lines = f.readlines()
        if lines:
            to_version = int(re.sub(r"\D", "", lines.pop().split()[-1]))
        else:
            return
        if self.from_version >= to_version:
            logging.debug("no need to update docs in database from version %s to version %s." , self.from_version, to_version)
            return
        
        docs_files = self.handle_lines(lines)
        try:
            logging.info("try to update docs in database from version %s to version %s." % (self.from_version, to_version))
            update_docs_in_db(self.project, docs_files, to_version)
        except BaseException, args:
            logging.error("%s:%s" % (args.__class__.__name__, args))
            logging.error("rollbacking database operations") 
            transaction.rollback()
            logging.error("rollbacked database operations") 
            logging.error("rollbacking docs in svn dir")
            if self.from_version:
                self.update(self.from_version)
            else:
                f=open_cmd("rm","-rf",self.svn_docs_dir)
            logging.error("rollbacked docs in svn dir")
        else:
            transaction.commit()
            
        